﻿using Common.Entitys.CommonLogs;
using Common.Utils;
using Newtonsoft.Json;
using ReactiveUI.Fody.Helpers;
using ReactiveUI;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Reactive;
using System.Text;
using System.Threading.Tasks;

namespace Common.ViewModels
{
    [Serializable]
    [JsonObject(MemberSerialization.OptOut)]
    public abstract class Axis : ViewModelBase, IPosition
    {

        public Axis()
        {
            VisualMoveCollector = new VisualMoveCollector(this);
        }

        [JsonIgnore]
        [Reactive] public bool Connected { get; set; } = false;

        [Reactive] public string Name { get; set; } = "";

        [Reactive] public bool NeedZero { get; set; } = true;

        [Reactive] public bool IsRemoved { get; set; } = false;

        [Reactive] public int 最大回零时间 { get; set; } = 13_000;

        [Reactive] public int ZeroSpeed { get; set; } = 30;

        /// <summary>
        /// 回零速度()
        /// </summary>
        [Reactive] public int ReturnZeroSpeed { get; set; }

        [Reactive]
        [JsonIgnore]
        public string ErrorInfo { get; set; }

        /// <summary>
        /// 是否移除
        /// </summary>
        [Reactive]
        public bool Removed { get; set; } = false;

        /// <summary>
        /// 当前速度
        /// </summary>
        [Reactive]
        [JsonIgnore]
        public double CSpeed { get; set; }

        /// <summary>
        /// 力矩
        /// </summary>
        [Reactive]
        [JsonIgnore]
        public int 力矩 { get; set; }

        #region 命令

        //public ReactiveCommand<Unit, Unit> CommandRemoevSelf => ReactiveCommand.Create(() =>
        //{
        //    ProductLine.Instance.Remove(this);
        //});

        /// <summary>
        /// 连接
        /// </summary>
        public ReactiveCommand<bool, Task> CommandConnect => ReactiveCommand.Create<bool, Task>(async (value) =>
        {
            try
            {
                if (value)
                {
                    await ConnectAsync();
                }
                else
                {
                    await DisconnectAsync();
                }

            }
            catch (Exception e)
            {
                MessageBoxService.Show(e.Message);
            }
        });

        /// <summary>
        /// 使能
        /// </summary>
        public ReactiveCommand<Unit, Task> CommandEnable => ReactiveCommand.Create(async () =>
        {
            try
            {
                if (this.Active == true)
                {
                    await this.CmdDisable();
                }
                else
                {
                    await this.CmdEnable();
                }
            }
            catch (Exception e)
            {
                MessageBoxService.Show(e.Message);
            }

        });

        public ReactiveCommand<Unit, Task> CommandJogSub => ReactiveCommand.Create(async () =>
        {
            try
            {
                await this.CmdJogNegative(DefaultSpeed);
            }
            catch (Exception e)
            {
                MessageBoxService.Show(e.Message);
            }
        });

        public ReactiveCommand<Unit, Task> CommandJogAdd => ReactiveCommand.Create(async () =>
        {
            try
            {
                await this.CmdJogPositive(DefaultSpeed);
            }
            catch (Exception e)
            {
                MessageBoxService.Show(e.Message);
            }
        });

        public ReactiveCommand<Unit, Task> CommandMoveStop => ReactiveCommand.Create(async () =>
        {
            try
            {
                await CmdStopAsync();
            }
            catch (Exception e)
            {
                MessageAggregator<ErrorMsg>.Publish(e.Message);
            }
        });

        /// <summary>
        /// 相对运动控制
        /// </summary>
        public ReactiveCommand<bool, Task> CommandMove => ReactiveCommand.Create<bool, Task>(async (value) =>
        {
            try
            {
                if (value)
                {
                    await CmdMoveInc(StepOfMoveInc, DefaultSpeed);
                }
                else
                {
                    await CmdMoveInc(-StepOfMoveInc, DefaultSpeed);
                }
            }
            catch (Exception e)
            {
                MessageBoxService.Show(e.Message);
            }
        });

        /// <summary>
        /// 回零
        /// </summary>
        public ReactiveCommand<bool, Task> CommandReturnZero => ReactiveCommand.Create<bool, Task>(async (value) =>
        {
            try
            {
                if (value)
                {
                    await CmdGoHome();
                }
                else
                {
                    await CmdAbordHome();
                }
            }
            catch (Exception e)
            {
                MessageBoxService.Show(e.Message);
            }
        });

        /// <summary>
        /// 复位
        /// </summary>
        public ReactiveCommand<Unit, Task> CommandReset => ReactiveCommand.Create<Task>(async () =>
        {
            try
            {
                await CmdClearFaultsAsync();
            }
            catch (Exception e)
            {
                MessageBoxService.Show(e.Message);
            }
        });
        #endregion



        public virtual Task ConnectAsync()
        {
            this.Connected = true;
            return Task.CompletedTask;
        }

        public virtual Task DisconnectAsync()
        {
            this.Connected = false;
            return Task.CompletedTask;
        }

        public void SetAlarm(AlarmCode code, string detail = null)
        {
            MessageAggregator<ErrorMsg>.Publish($"轴 ：{this.Name}  报警 {code.ToString()}   {detail} ");
        }

        public void SetAlarm(AlarmCode code, Exception e)
        {
            MessageAggregator<ErrorMsg>.Publish($"轴 ：{this.Name}  报警 {code.ToString()}   {e.Message} ");
        }

        public void Log(string msg, Exception e)
        {
            ErrorLogEntity errorLogEntity = new ErrorLogEntity(msg, e);
            LogHelp.AddLog<ErrorLogEntity>(msg);
        }

        #region ScanInterval
        protected int scanInterval = 50;
        [DisplayName("扫描周期")]
        public int ScanInterval
        {
            get { return scanInterval; }
            set
            {
                if (value == scanInterval) return;
                scanInterval = value;
                ;
                OnPropertyChanged(ScanIntervalProperty);
            }
        }
        public static PropertyChangedEventArgs ScanIntervalProperty = new PropertyChangedEventArgs(nameof(ScanInterval));
        #endregion

        #region Status
        /// <summary>
        /// 状态未知,初始状态不能为Stoped,万一遭到没有连上,就会出现Bug
        /// </summary>
        [JsonIgnore]
        protected CarStatus status = CarStatus.Unknow;
        /// <summary>
        /// 当前状态
        /// </summary>
        [Browsable(false)]
        [JsonIgnore]
        [Reactive]
        public CarStatus Status
        {
            get => status;
            set
            {
                if (value == status)
                {
                    return;
                }
                status = value;
                this.RaisePropertyChanged();
            }
        }
        public static PropertyChangedEventArgs StatusProperty = new PropertyChangedEventArgs(nameof(Status));
        #endregion        

        #region FltCount
        private int fltCount;
        /// <summary>
        /// 故障数量
        /// </summary>
        [JsonIgnore]
        [Browsable(false)]
        public int FltCount
        {
            get { return fltCount; }
            set
            {
                if (value == fltCount) return;
                fltCount = value;
                OnPropertyChanged(FltCountProperty);
            }
        }
        public static PropertyChangedEventArgs FltCountProperty = new PropertyChangedEventArgs(nameof(FltCount));
        #endregion

        #region WrnCount
        [JsonIgnore]
        private int wrnCount;
        /// <summary>
        /// 报警数量
        /// </summary>
        [JsonIgnore]
        [Browsable(false)]
        public int WrnCount
        {
            get { return wrnCount; }
            set
            {
                if (value == wrnCount) return;
                wrnCount = value;
                OnPropertyChanged(WrnCountProperty);
            }
        }
        public static PropertyChangedEventArgs WrnCountProperty = new PropertyChangedEventArgs(nameof(WrnCount));
        #endregion

        #region SoftOffset
        private double softOffset;
        /// <summary>
        /// 软偏移(最大5mm)
        /// </summary>
        public double SoftOffset
        {
            get { return softOffset; }
            set
            {
                if (value == softOffset) return;
                softOffset = value;
                ;
                OnPropertyChanged(SoftOffsetProperty);
            }
        }
        public static PropertyChangedEventArgs SoftOffsetProperty = new PropertyChangedEventArgs(nameof(SoftOffset));
        #endregion

        #region Location
        [JsonIgnore]
        private System.Windows.Point location;
        [Browsable(false)]
        [JsonIgnore]
        public System.Windows.Point Location
        {
            get { return location; }
            set
            {
                if (value == location) return;
                location = value;
                OnPropertyChanged(LocationProperty);
            }
        }
        public static PropertyChangedEventArgs LocationProperty = new PropertyChangedEventArgs(nameof(Location));
        #endregion

        #region Position
        [JsonIgnore]
        double position = double.NaN;
        /// <summary>
        /// 当前坐标
        /// </summary>
        [Browsable(false)]
        [DisplayName("当前位置")]
        [Description("为空时表示还未获取到当前位置")]
        [JsonIgnore]
        public double Position
        {
            get => position;
            set
            {
                if (value == position) return;
                position = value;
                this.RaisePropertyChanged();
                //OnPropertyChanged(PositionProperty);
            }
        }
        public static PropertyChangedEventArgs PositionProperty = new PropertyChangedEventArgs(nameof(Position));
        #endregion

        #region Active
        [JsonIgnore]
        bool? active;
        /// <summary>
        /// 是否使能
        /// </summary>
        [JsonIgnore]
        [Browsable(false)]
        public bool? Active
        {
            get => active;
            set
            {
                if (value == active)
                    return;
                active = value;
                Trace.WriteLine($"{this} active {value}");
                this.RaisePropertyChanged();
                //OnPropertyChanged(ActiveProperty);
            }
        }
        public static PropertyChangedEventArgs ActiveProperty = new PropertyChangedEventArgs(nameof(Active));
        #endregion

        #region MinPosition
        double minPosition;
        public double MinPosition
        {
            get => minPosition;
            set
            {
                if (value == minPosition) return;
                minPosition = value;
                ;
                OnPropertyChanged(MinPositionProperty);
            }
        }
        public static PropertyChangedEventArgs MinPositionProperty = new PropertyChangedEventArgs(nameof(MinPosition));
        #endregion

        #region 
        [JsonIgnore]
        private HomeState homeState = HomeState.Unknown;
        [JsonIgnore]
        [Browsable(false)]
        [DisplayName("回零状态")]
        public HomeState HomeState
        {
            get { return homeState; }
            set
            {
                if (value == homeState) return;
                homeState = value;
                this.RaisePropertyChanged();
            }
        }
        public static PropertyChangedEventArgs HomeStateProperty = new PropertyChangedEventArgs(nameof(HomeState));
        #endregion

        #region PositiveLimitActive
        [JsonIgnore]
        private bool? positiveLimitActive;
        /// <summary>
        /// 正限位生效
        /// </summary>
        [Browsable(false)]
        [Newtonsoft.Json.JsonIgnore]
        public bool? PositiveLimitActive
        {
            get { return positiveLimitActive; }
            set
            {
                if (value == positiveLimitActive) return;
                positiveLimitActive = value;
                OnPropertyChanged(PositiveLimitActiveProperty);
            }
        }
        public static PropertyChangedEventArgs PositiveLimitActiveProperty = new PropertyChangedEventArgs(nameof(PositiveLimitActive));
        #endregion

        #region NegativeLimitActive
        [JsonIgnore]
        private bool? negativeLimitActive;
        /// <summary>
        /// 负限位生效
        /// </summary>
        [Browsable(false)]
        [Newtonsoft.Json.JsonIgnore]
        public bool? NegativeLimitActive
        {
            get { return negativeLimitActive; }
            set
            {
                if (value == negativeLimitActive) return;
                negativeLimitActive = value;
                OnPropertyChanged(NegativeLimitActiveProperty);
            }
        }
        public static PropertyChangedEventArgs NegativeLimitActiveProperty = new PropertyChangedEventArgs(nameof(NegativeLimitActive));
        #endregion

        #region ZRotate
        [JsonIgnore]
        private double zRotate;
        [Browsable(false)]
        public double ZRotate
        {
            get { return zRotate; }
            set
            {
                if (value == zRotate) return;
                zRotate = value;
                OnPropertyChanged(ZRotateProperty);
            }
        }
        public static PropertyChangedEventArgs ZRotateProperty = new PropertyChangedEventArgs(nameof(ZRotate));
        #endregion

        #region TargetPosition
        [JsonIgnore]
        private double? targetPosition;
        [Browsable(false)]
        [JsonIgnore]
        public double? TargetPosition
        {
            get { return targetPosition; }
            set
            {
                targetPosition = value;
            }
        }
        public static PropertyChangedEventArgs TargetPositionProperty = new PropertyChangedEventArgs(nameof(TargetPosition));
        #endregion

        #region DefaultSpeed
        int defaultSpeed = 10;
        [DisplayName("默认速度")]
        public int DefaultSpeed
        {
            get => defaultSpeed;
            set
            {
                defaultSpeed = value;
                ;
                OnPropertyChanged(DefaultSpeedProperty);
            }
        }
        public static PropertyChangedEventArgs DefaultSpeedProperty = new PropertyChangedEventArgs(nameof(DefaultSpeed));
        #endregion

        #region StepOfMoveInc
        private double stepOfMoveInc = 10;
        /// <summary>
        /// 寸动量
        /// </summary>
        public double StepOfMoveInc
        {
            get { return stepOfMoveInc; }
            set
            {
                if (value == stepOfMoveInc) return;
                stepOfMoveInc = value;
                ;
                OnPropertyChanged(StepOfMoveIncProperty);
            }
        }
        public static PropertyChangedEventArgs StepOfMoveIncProperty = new PropertyChangedEventArgs(nameof(StepOfMoveInc));
        #endregion

        #region DisableManualHome
        private bool disableManualHome;
        /// <summary>
        /// 禁用手动回零
        /// </summary>
        public bool DisableManualHome
        {
            get { return disableManualHome; }
            set
            {
                if (value == disableManualHome) return;
                disableManualHome = value;
                ;
                OnPropertyChanged(DisableManualHomeProperty);
            }
        }
        public static PropertyChangedEventArgs DisableManualHomeProperty = new PropertyChangedEventArgs(nameof(DisableManualHome));
        #endregion

        /// <summary>
        /// 警告代码
        /// </summary>
        [DisplayName("驱动器报警代码集合")]
        [Browsable(false)]
        [JsonIgnore]
        public List<int> WrnCodes { get; } = new List<int>();

        [DisplayName("驱动器故障代码集合")]
        [Browsable(false)]
        [JsonIgnore]
        public List<int> FltCodes { get; } = new List<int>();


        public int LostTimes { get; set; }

        [Reactive] public bool EnableLog { get; set; } = false;

        [JsonIgnore]
        public VisualMoveCollector VisualMoveCollector;

        public event PropertyChangedEventHandler PropertyChanged;


        protected void OnPropertyChanged(PropertyChangedEventArgs args)
        {
            PropertyChanged?.Invoke(this, args);
        }


        #region async cmds
        public abstract Task<ResponseCode> CmdMoveInc(double pos, int speed);

        public virtual Task<ResponseCode> CmdMoveAbs(double pos, int speed)
        {
            LogHelp.AddLog<FtpCarLog>(new FtpCarLog($"从{this.Position}移动至{pos} 速度{speed}") { CarName = this.Name });
            VisualMoveCollector.CmdMoveAbs(pos, speed, out _);
            return Task.FromResult(ResponseCode.SUCCESS);

        }

        //public void MoveAndWait(double pos, int speed)
        //{
        //    this.CmdMoveAbs(pos, speed);
        //    while (true)
        //    {
        //        double offset=this.Position- pos
        //       if (this.Position==)
        //    }
        //}

        public abstract Task CmdStopAsync();

        //public abstract Task CmdStop();


        public virtual Task<ResponseCode> CmdEnable()
        {
            this.Active = true;
            return Task.FromResult(ResponseCode.SUCCESS);
        }

        public virtual Task CmdDisable()
        {
            this.Active = false;
            return Task.FromResult(ResponseCode.SUCCESS);
        }

        public virtual Task<ResponseCode> CmdGoHome()
        {
            Thread.Sleep(1000);
            this.HomeState = HomeState.Completed;
            this.Position = 0;
            return Task.FromResult(ResponseCode.SUCCESS);
        }

        public virtual Task CmdAbordHome()
        {
            this.HomeState = HomeState.Idle;
            return Task.FromResult(ResponseCode.SUCCESS);
        }

        public abstract Task<double> CmdGetPosAsync();

        public abstract Task<bool> CmdGetActive();

        public abstract Task<bool> CmdGetMoving();

        public abstract Task<HomeState> CmdGetHomeState();

        public abstract Task CmdClearFaultsAsync();

        public abstract Task<ResponseCode> CmdJogPositive(int speed);

        public abstract Task<ResponseCode> CmdJogNegative(int speed);

        public abstract Task CmdSetHomeOffset(double offset);

        public virtual Task ValidDeviceConfigAsync()
        {
            return Task.CompletedTask;
        }

        public virtual Task ConfigDeviceAsync()
        {
            return Task.CompletedTask;
        }

        #endregion

    }
}
